//FAS低代码开发平台
//变更日志插件: 针对CUD操作记录变更日志，其中新增、修改的克隆TRecord逻辑是避免状态机插件【保存后事件】影响返给前端的TRecord内容
//新增：
//    1、前端NewTRecord A传入后【BeforeExecuteSQL】做初次变更比较（没有OldValue），为A生成ChangeSet供状态机【保存前事件】Action脚本使用
//    2、数据落盘后【Finish】，从DB中取出最新NewTRecord B（获取DB默认值），克隆NewTRecord C，将B传入插件，再次做变更比较。
//       此时生成的变更为包含状态机脚本更新后的最新变更，直接生成大数据日志，而后执行状态机的【保存后事件】
//    3、将C返回给前端。
//修改：
//    1、前端NewTRecord A传入后【BeforeExecuteSQL】，获取DB中的OldRecord，做变更比较，将NewTRecord A,OldValue传入供状态机【保存前事件】Action脚本使用
//    2、状态机【保存前事件】执行完毕后（A的ChangeSet已包含最新变更），克隆NewTRecord B，
//       数据落盘后【Finish】，将A传入变更日志插件中，直接生成大数据日志。而后执行状态机的【保存后事件】
//    3、将最新的时间戳赋值给B后返回前端。
//删除：
//    1、由于删除不走状态机逻辑，故在【BeforeExecuteSQL】时，变更日志插件中生成TRecord实例，只记录主键id变更，放到上下文中
//    2、数据落盘后【Finish】，在上下文中拿到生成的TRecord实例，生成大数据日志
//    3、删除不向前端返回数据
//===============================================================================
//变更历史纪录
//日期			版本	修改人	描述
//===============================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.DataAccess.Common;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.Log.SPI;

namespace T.FAS.Runtime.DataAccess.Engine
{

    /// <summary>
    /// 新建的变更日志
    /// </summary>
    public class CreateChangeLog : AbstractChangeLog
    {
        [Obsolete("不再使用")]
        public override DataChangeLog LogBigDataChangeLog(ChangeLogContext changeLogContext)
        {
            if (changeLogContext.CurrentData == null || changeLogContext.CompositeDataObject == null)
                return null;
            var changeItem = GetBigDataCreateRecordChangeRecursive(changeLogContext.CompositeDataObject.RootCompositeNodeObject, new List<TRecord> { changeLogContext.CurrentData });
            var dataChangeLog = base.CreateNewBigDataChangeLog(changeLogContext);
            dataChangeLog.FillDefaultField(changeLogContext.CurrentData);   //填充最后修改人
            dataChangeLog.CreateTime = DACContextHelper.GetTimestamp(); //新增时间的时间戳从线程上下文中获取
            dataChangeLog.Datas = changeItem;
            #region 新增变更判断状态机是否存在，处理初始事件状态
            List<StateMachineMetadata> stateMachines = InitCDOStateMachine(changeLogContext.CompositeDataObject);
            foreach (var machine in stateMachines)
            {
                try
                {
                    string stateColKey = machine.CDOColKey;
                    var newState = int.Parse(changeLogContext.CurrentData.GetValue(stateColKey).ToString());
                    TState tNewState = machine.States.FirstOrDefault(s => s.Key == newState);
                    if (tNewState != null)
                    {
                        dataChangeLog.Ext13 = tNewState.Key.ToString();
                        dataChangeLog.Ext14 = tNewState.Name;
                    }
                }
                catch (Exception e)
                {
                    throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.AbstractChangeLog_ChangeLogPluginExecFail,changeLogContext.CompositeDataObject.Code,machine.Code,changeLogContext.CurrentData), e);
                }
            }
            #endregion
            return dataChangeLog;
        }


        [Obsolete("不再使用")]
        public override TChangeLog LogChange(ChangeLogContext changeLogContext)
        {
            if (changeLogContext.CurrentData == null || changeLogContext.CompositeDataObject == null)
                return null;
            var changeSet = base.CreateDataChangeSet(changeLogContext);
            changeSet.ModifyTime = DACContextHelper.GetTimestamp(); //新增时间的时间戳从线程上下文中获取
            ChangeSetTemplate = changeSet;  //暂存ChangeSet基本信息模板
            var changeSets = GetCreateRecordChangeRecursive(changeLogContext.CompositeDataObject.RootCompositeNodeObject, new List<TRecord> { changeLogContext.CurrentData });
            
            #region 新增变更判断状态机是否存在，处理初始事件状态
            List<StateMachineMetadata> stateMachines = InitCDOStateMachine(changeLogContext.CompositeDataObject);
            foreach (var machine in stateMachines)
            {
                try
                {
                    string stateColKey = machine.CDOColKey;
                    var newState = int.Parse(changeLogContext.CurrentData.GetValue(stateColKey).ToString());
                    TState tNewState = machine.States.FirstOrDefault(s => s.Key == newState);
                    if (tNewState != null)
                    {
                        changeSet.NewStateCode = tNewState.Key.ToString();
                        changeSet.NewStateName = tNewState.Name;
                    }
                }
                catch (Exception e)
                {
                    throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.AbstractChangeLog_ChangeLogPluginExecFail, changeLogContext.CompositeDataObject.Code,machine.Code,changeLogContext.CurrentData), e);
                }
            }
            #endregion
            return changeSets.FirstOrDefault();
        }

        /// <summary>
        /// 记录变更集
        /// </summary>
        /// <param name="changeLogContext"></param>
        /// <returns></returns>
        public override TRecord LogChangeSet(ChangeLogContext changeLogContext)
        {
            if (changeLogContext.CurrentData == null || changeLogContext.CompositeDataObject == null)
                return null;

            InitBasicChangeInfo();
            //BasicChangeInfo.ModifyTime = DACContextHelper.GetTimestamp();   //新增时间的时间戳从线程上下文中获取

            //填充所有节点的ChangeSet信息
            ChangeLogControlContext controlContext = InitChangeLogControlContext(changeLogContext);
            GetCreateChangeSetRecursive(changeLogContext.CompositeDataObject.RootCompositeNodeObject, new List<TRecord> { changeLogContext.CurrentData }, controlContext);
            changeLogContext.CurrentData.ChangeType = TRecordChangeType.Add;
            #region 新增变更判断状态机是否存在，处理初始事件状态
            List<StateMachineMetadata> stateMachines = InitCDOStateMachine(changeLogContext.CompositeDataObject);
            foreach (var machine in stateMachines)
            {
                try
                {
                    string stateColKey = machine.CDOColKey;
                    //为TRecord状态字段赋值，方便后续SetValue时，不丢失列的BusinessType
                    if (changeLogContext.CurrentData.StateColumnNames == null)
                        changeLogContext.CurrentData.StateColumnNames = new List<string>();
                    changeLogContext.CurrentData.StateColumnNames.Add(stateColKey);
                    var newStateVal = changeLogContext.CurrentData.GetValue(stateColKey)?.ToString();
                    if(string.IsNullOrEmpty(newStateVal))
                        throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.CreateChangeLog_LogChangeSet,changeLogContext.CompositeDataObject.Code,machine.Code));
                    var newState = int.Parse(newStateVal);
                    TState tNewState = machine.States.FirstOrDefault(s => s.Key == newState);
                    if (tNewState != null)
                    {
                        var StateChangeItem = changeLogContext.CurrentData.ChangeSet.ChangeSetItems.FirstOrDefault(item => item.ColumnCode == machine.CDOColKey);
                        StateChangeItem.BusinessType = BusinessType.State;
                        StateChangeItem.NewValue = tNewState.Key.ToString();
                        StateChangeItem.NewDisplayValue = tNewState.Name;
                    }
                }
                catch (Exception e)
                {
                    throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.AbstractChangeLog_ChangeLogPluginExecFail, changeLogContext.CompositeDataObject.Code,machine.Code,changeLogContext.CurrentData), e);
                }
            }
            #endregion
            return changeLogContext.CurrentData;
        }
    }
}
